package com.atguigu.gulimall.ware.listener;

import com.atguigu.common.contrsant.WareConstant;
import com.atguigu.common.dto.OrderDTO;
import com.atguigu.common.dto.mq.StockLockDTO;
import com.atguigu.common.exception.BusinessException;
import com.atguigu.gulimall.ware.service.WareSkuService;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * @author meiyn
 * @date 2021/7/23 18:01
 */
@Service
@RabbitListener(queues = WareConstant.STOCK_RELEASE_STOCK_QUEUE)
public class StockReleaseListener {
    @Resource
    private WareSkuService wareSkuService;

    /**
     * 监听自动解锁
     * 1.订单取消、超时
     * 2.下单时，库存锁定成功，但执行订单服务后面逻辑异常，订单回滚成功。
     *
     * @param stockLockDTO
     */
    @RabbitHandler
    public void handleStockLockRelease(StockLockDTO stockLockDTO, Message message, Channel channel) throws IOException {
        System.out.println("收到自动解锁库存的消息");

        try {
            wareSkuService.unlockStock(stockLockDTO);
            //手动回复RabbitMQ，订单已经解锁成功，broker将移除此消息
            //multiple: 不用批量模式
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (BusinessException e) {
            //订单解锁异常，消息拒绝，重新放入消息队列，让别人继续解锁消费
            //requeue：拒绝消息
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
        }
    }

    /**
     * 监听主动解锁库存的消息
     *
     * 场景：卡顿订单，永远不会解锁库存？
     *      下单时，订单调用库存成功，但是由于订单系统卡顿，网络等原因，订单卡住了
     *      假如卡了两分钟，这时候库存服务去自动解锁库存，发现订单还是创建状态，就没有解锁库存；
     *      但是订单服务恢复后，这单要关单，所以最终，库存永远不会解锁。
     *
     *   解决：订单关闭后，也主动发送消息（路由键需要跟库存的交换机绑定，发送到库存队列）
     */
    @RabbitHandler
    public void handleUnlock(OrderDTO orderDTO, Message message, Channel channel) throws IOException {
        System.out.println("收到主动解锁库存的消息");

        try {
            wareSkuService.unlockStock(orderDTO);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (BusinessException e) {
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
        }
    }
}
